package com.noassertions.data;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;

import com.noassertions.domain.Comment;
import com.noassertions.domain.Fit;
import com.noassertions.domain.Image;
import com.noassertions.domain.Rider;
import com.noassertions.domain.User;

public class DAOImpl extends HibernateDaoSupport implements DAOInterface
{

    protected final Log log = LogFactory.getLog(getClass());
  
    // TODO: genericize these common methods (create, delete, etc.)
    @Transactional
    public void insertUser(User user)
    {
    	getHibernateTemplate().saveOrUpdate(user);	
    }
       
    @Transactional
    public void insertRider(Rider rider)
    {
    	getHibernateTemplate().saveOrUpdate(rider);
    }

    
    @Transactional(readOnly = true)
	public ArrayList getAllRiders() {
        DetachedCriteria dCriteria = DetachedCriteria.forClass(Rider.class);
        ArrayList riderList = (ArrayList) getHibernateTemplate().findByCriteria(dCriteria);
		return riderList;
	}
    
    @Transactional
    public void saveFit(Fit fit) {
    	getHibernateTemplate().saveOrUpdate(fit);
    }
    
    @Transactional(readOnly = true)
	public ArrayList getAllFits() {
        DetachedCriteria dCriteria = DetachedCriteria.forClass(Fit.class);
        dCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        ArrayList fitList = (ArrayList) getHibernateTemplate().findByCriteria(dCriteria);
		return fitList;
	}
    
    @Transactional
    public void saveComment(Comment comment) {
    	getHibernateTemplate().saveOrUpdate(comment);
    }
    
    @Transactional
    public void saveImage(Image image) {
    	getHibernateTemplate().saveOrUpdate(image);
    }
    
    @Transactional(readOnly = true)
	public Rider getRiderByID(int id)
	{
		Rider rider = (Rider) getHibernateTemplate().get(Rider.class, id);
		return rider;
	}
    
    /**
     * Find the total number of riders in the system
     * This is typically used as an ceiling when grabbing a rider by a random number
     * 
     * @return count of riders in system
     */
    @Transactional
    public Long getRiderCount() {
    	String query = "select count(*) from Rider";
    	//TODO: Update so that iterator isn't created to get count
    	return (((Long) getHibernateTemplate().find(query).iterator().next()).longValue());
    }
    
    /**
     * 
     * Find the count of fits a rider has in the fit table
     * 
     * @param riderId the id of the rider we're looking for
     * @return count of fits for a given rider
     */
    @Transactional
    public Long getFitCount(int riderId) {
    	String query = "from Fit where userid = ?";
    	//TODO: Update so that iterator isn't created to get count

    	return (((Long) getHibernateTemplate().find(query).iterator().next()).longValue());
    }

    @Transactional(readOnly = true)
	public ArrayList getUserByUserId(int userid) {
    	//TODO: we're only ever going to get one rider, do we need a list?
    	String query = "from User where userid = ?";
		ArrayList riderList = (ArrayList)getHibernateTemplate().find(query, userid);
		return riderList;
	}

    @Transactional(readOnly = true)
	public User getUserByFitId(int fitid) {
    	// Is this really the best way to get a user out of hibernate?
    	// Seems like a lot of work
        DetachedCriteria dCriteria = DetachedCriteria.forClass(Fit.class);
        Criterion criterion =  Restrictions.eq("fitid", fitid);
    	dCriteria.add(criterion);
        ArrayList fitList = (ArrayList) getHibernateTemplate().findByCriteria(dCriteria);
    	
        User user = new User();
        if (fitList.size() > 0) {
        	Fit fit = (Fit) fitList.get(0);
        	dCriteria = DetachedCriteria.forClass(User.class);
        	criterion =  Restrictions.eq("userid", fit.getUserid());
        	dCriteria.add(criterion);
        	ArrayList userList =  (ArrayList) getHibernateTemplate().findByCriteria(dCriteria);
        	if (userList.size() > 0) {
        		user = (User) userList.get(0);
        	}
        }
		return user;
	}
    
    @Transactional(readOnly = true)
	public Fit getFitByFitId(int fitid) {
    	String query = "from Fit where fitid = ?";
    	// TODO: there must be a better way than getting the first (and only) element in the list
		ArrayList fitList = (ArrayList)getHibernateTemplate().find(query, fitid);
		return (Fit) fitList.get(0);
	}
    
    @Transactional(readOnly = true)
	public ArrayList getRiderByUserId(int userid) {
    	//TODO: we're only ever going to get one rider, do we need a list?
    	String query = "from Rider where userid = ?";
		ArrayList riderList = (ArrayList)getHibernateTemplate().find(query, userid);
		return riderList;
	}
    
    @Transactional(readOnly = true)
	public ArrayList getFitsByUserId(int userid) {
    	
    	String query = "from Fit where userid = ?";
		ArrayList fitList = (ArrayList)getHibernateTemplate().find(query, userid);
		return fitList;
	}

    @Transactional(readOnly = true)
	public ArrayList getImagesByFitId(int fitId) {
    	String query = "from Image where fitid = ?";
		ArrayList imageList = (ArrayList)getHibernateTemplate().find(query, fitId);
		return imageList;
	}
    
    @Transactional(readOnly = true)
	public ArrayList getCommentsByFitId(int fitId) {
    	String query = "from Comment where fitid = ?";
		ArrayList commentList = (ArrayList)getHibernateTemplate().find(query, fitId);
		return commentList;
	}
    
    @Transactional(readOnly = true)
	public Comment getCommentByCommentId(int commentId)
	{
		Comment comment = (Comment) getHibernateTemplate().get(Comment.class, commentId);
		return comment;
	}
    
    @Transactional(readOnly = true)
	public ArrayList getAllComments() {
        DetachedCriteria dCriteria = DetachedCriteria.forClass(Comment.class);
        dCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        ArrayList commentList = (ArrayList) getHibernateTemplate().findByCriteria(dCriteria);
		return commentList;
	}
    

	public User getUserByemailAddress(String emailAddress) {
		log.debug("looking for: " + emailAddress);
		String query = "from User where emailaddress = ?";
		ArrayList<User> userList = (ArrayList<User>)getHibernateTemplate().find(query, emailAddress);

		// returning null isn't nice, so return an empty user if we didn't find anything
		if (userList.size() == 0) {
			User emptyUser = new User();
			userList.add(emptyUser);
		}
		
		return (User) userList.get(0);
	}

	public User getRandomUserByUserid() {
		String query = "from User where completeprofile=1 order by rand()";
		ArrayList<User> userList = (ArrayList<User>)getHibernateTemplate().find(query);

		// returning null isn't nice, so return an empty user if we didn't find anything
		if (userList.size() == 0) {
			User emptyUser = new User();
			userList.add(emptyUser);
		}
		
		return (User) userList.get(0);
	}
}